import datetime
from typing import Type

from sqlalchemy import or_, func, Integer, select, text, outerjoin
from sqlalchemy.orm import Session

from module_admin.entity.do.cms_driver import CmsDriver
from module_admin.entity.do.cms_order import CmsOrder
from module_admin.entity.do.cms_order_dispatch import CmsOrderDispatch
from module_admin.entity.do.cms_order_execute import CmsOrderExecute
from module_admin.entity.vo.cms_driver_vo import DriverModel, DriverForQuery, DriverModelFree
from module_admin.entity.vo.cms_home_vo import MyTime
from module_admin.enum.state_enum import OrderStateEnum
from utils.stringUtils import stringUtils
from utils.time_format_util import object_format_datetime, list_format_datetime


class CmsDriverDao:

    @classmethod
    def get_one_by_id(cls, db: Session, id: int):
        first = db.query(CmsDriver).filter(CmsDriver.id == id).first()
        first.password = ""
        return object_format_datetime(first)

    @classmethod
    def get_one_by_driver_id(cls, db: Session, driver_id: str):
        first = db.query(CmsDriver).filter(CmsDriver.driver_id == driver_id).first()
        first.password = ""
        return object_format_datetime(first)

    @classmethod
    def create_driver(cls, db: Session, page_object: DriverModel, driver_model: str):
        object_dict = page_object.dict()
        if "driver_model_list" in object_dict:
            del object_dict["driver_model_list"]
        cms_driver = CmsDriver(**object_dict)
        cms_driver.driver_model = driver_model;
        db.add(cms_driver)
        db.flush()
        return cms_driver

    @classmethod
    def delete_driver_by_id(cls, db: Session, id: int):
        db.query(CmsDriver) \
            .filter(CmsDriver.id == id) \
            .delete()

    @classmethod
    def update_driver_by_id(cls, db: Session, driver_update_dict: dict):
        db.query(CmsDriver) \
            .filter(CmsDriver.id == driver_update_dict.get('id')) \
            .update(driver_update_dict)

    @classmethod
    def list(cls, db: Session, query_object: DriverForQuery):
        query = db.query(CmsDriver)
        filters = []
        if query_object.driver_name and query_object.driver_name.strip():
            filters.append(or_(CmsDriver.driver_name.like(f'%{query_object.driver_name}%'),
                               CmsDriver.driver_id.like(f'%{query_object.driver_name}%')))
        if query_object.driver_id and query_object.driver_id.strip():
            filters.append(CmsDriver.driver_id == query_object.driver_id)
        if query_object.phone and query_object.phone.strip():
            filters.append(CmsDriver.phone == query_object.phone)
        if filters:
            query = query.filter(*filters)
        post_list = query.order_by(CmsDriver.create_time.desc()).all()
        for post in post_list:
            post.password = ""
        return list_format_datetime(post_list)

    @classmethod
    def list_all(cls, db: Session, new_plan_begin_time: datetime, new_plan_end_time: datetime):
        driver__all = db.query(CmsDriver).all()
        driver_id_list = None
        if new_plan_begin_time is not None:
            driver_sub = db.query(CmsDriver.id) \
                .outerjoin(CmsOrderDispatch, CmsOrderDispatch.driver_id == CmsDriver.driver_id) \
                .outerjoin(CmsOrder, CmsOrderDispatch.order_id == CmsOrder.order_id) \
                .filter(CmsOrder.plan_begin_time < new_plan_end_time) \
                .filter(CmsOrder.plan_end_time > new_plan_begin_time) \
                .all()
            driver_id_list = {CmsDriver.id for CmsDriver in driver_sub}
        list0 = []
        for e in driver__all:
            e.password = ""
            driver_dict = cls.del_and_add_driver_model(e)
            model = DriverModelFree(**driver_dict)
            model.driver_state = "任务中" if driver_id_list is not None and model.id in driver_id_list else "空闲"
            list0.append(model)
        return list_format_datetime(list0)

    @classmethod
    def list_free(cls, db: Session, new_plan_begin_time: datetime, new_plan_end_time: datetime):
        subquery = (db.query(CmsDriver.id)
                    .outerjoin(CmsOrderDispatch, CmsOrderDispatch.driver_id == CmsDriver.driver_id)
                    .outerjoin(CmsOrder, CmsOrderDispatch.order_id == CmsOrder.order_id)
                    .filter(CmsOrder.plan_begin_time < new_plan_end_time)
                    .filter(CmsOrder.plan_end_time > new_plan_begin_time)
                    .subquery())
        result = db.query(CmsDriver) \
            .filter(CmsDriver.id.notin_(subquery)) \
            .all()
        for e in result:
            e.password = ""
        return list_format_datetime(result)

    @classmethod
    def have_jxz(cls, db: Session, driver_id: str):
        result = db.query(CmsDriver) \
            .outerjoin(CmsOrderDispatch, CmsOrderDispatch.driver_id == CmsDriver.driver_id) \
            .outerjoin(CmsOrder, CmsOrderDispatch.order_id == CmsOrder.order_id) \
            .filter(CmsOrder.state == OrderStateEnum.jxz.value) \
            .filter(CmsOrderDispatch.driver_id == driver_id) \
            .all()
        if result and len(result) > 0:
            return True
        else:
            return False

    @classmethod
    def order_satrt_driver_num(cls, db: Session, time: MyTime):
        mileage = db.query(func.count(CmsDriver.id)) \
            .join(CmsOrderExecute, CmsOrderExecute.driver_id == CmsDriver.driver_id) \
            .filter(CmsOrderExecute.create_time >= time.start_time.strftime('%Y-%m-%d %H:%M:%S')) \
            .filter(CmsOrderExecute.create_time < time.end_time.strftime('%Y-%m-%d %H:%M:%S')) \
            .scalar()
        return mileage if mileage is not None else 0

    @classmethod
    def del_and_add_driver_model(cls, driver_by_id: CmsDriver):
        driver_model_list = stringUtils.get_list(driver_by_id.driver_model)
        driver_dict = driver_by_id.__dict__
        if "driver_model" in driver_dict:
            del driver_dict["driver_model"]
        driver_dict.setdefault("driver_model_list", driver_model_list)
        return driver_dict
